﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Sql;
using System.Data.SqlClient;
using System.Windows;

namespace XMM.Objects
{
    public class Movie : Object
    {
        /// <summary>
        /// Database-Record ID.
        /// </summary>
        public int MovieID { get; set; }

        /// <summary>
        /// Movie-Name.
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// Subtitle.
        /// </summary>
        public string Subtitle { get; set; }

        /// <summary>
        /// Genre-Database-Record ID
        /// </summary>
        public int GenreID { get; set; }

        /// <summary>
        /// Plot (Description).
        /// </summary>
        public string Plot { get; set; }

        /// <summary>
        /// Involved Actors.
        /// </summary>
        public string Cast { get; set; }

        /// <summary>
        /// Director of the Movie.
        /// </summary>
        public string Director { get; set; }

        /// <summary>
        /// Release Year.
        /// </summary>
        public int Year { get; set; }

        /// <summary>
        /// Media-Files linked to this Movie.
        /// </summary>
        public List<string> Files { get; set; }

        /// <summary>
        /// Info for all detected audio-tracks within the file.
        /// </summary>
        public Objects.AudioInfo AudioInfo { get; set; }

        /// <summary>
        /// Info for all detected video-tracks within the file.
        /// </summary>
        public Objects.VideoInfo VideoInfo { get; set; }

        /// <summary>
        /// MediaID of the Disk that contains the file.
        /// </summary>
        /// <remarks>Use 0 for single (separate) media.</remarks>
        public int DiskMediaID { get; set; }

        /// <summary>
        /// Content HD-Type.
        /// </summary>
        /// <remarks>0...Standard Definition (SD)
        /// 1...HD 720p
        /// 2...HD 1080i
        /// 3...HD 1080p</remarks>
        public int HDLevel { get; set; }

        public string OnlineMediaID { get; set; }

        /// <summary>
        /// Initialize a new Movie-Object with blank Values.
        /// </summary>
        public Movie()
        {
            blankValues();
        }

        /// <summary>
        /// Initialize a new Movie-Object and load info from database.
        /// </summary>
        /// <param name="iMovieID">(int) Target-Movie-ID.</param>
        public Movie(int iMovieID)
        {
            blankValues();

            Load(iMovieID);
        }

        /// <summary>
        /// Initialize a new Movie-Object from a FileName.
        /// </summary>
        /// <param name="FileName">(string) Full path to any file linked to this movie.</param>
        public Movie(string FileName)
        {
            blankValues();

            try
            {
                XMMDBDataContext dbConnection = new XMMDBDataContext();

                var vMovies = from movie in dbConnection.t_movies select movie;

                if (vMovies != null)
                {
                    foreach (t_movies vMovie in vMovies)
                    {
                        if (vMovie.Files.Contains(FileName))
                        {
                            Load(vMovie.ID);

                            break;
                        }
                    }
                }
            }
            catch (SqlException ex)
            {
                MessageBox.Show("Fehler beim Suchen der Datei \"" + FileName + "\" in der Datenbank: " + ex.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        /// <summary>
        /// Reset all values.
        /// </summary>
        public void blankValues()
        {
            MovieID = 0;
            Name = String.Empty;
            Subtitle = String.Empty;
            GenreID = 0;
            Plot = String.Empty;
            Cast = String.Empty;
            Director = String.Empty;
            Year = 0;
            Files = new List<string>();
            AudioInfo = new Objects.AudioInfo();
            VideoInfo = new Objects.VideoInfo();
            HDLevel = 0;
            DiskMediaID = 0;
            OnlineMediaID = String.Empty;
        }

        public override string ToString()
        {
            return Name;
        }

        /// <summary>
        /// Load a specific movie from database.
        /// </summary>
        /// <param name="iMovieID">(int) Target-Movie-ID.</param>
        /// <returns>[true] if movie was loaded successfully.</returns>
        public bool Load(int iMovieID)
        {
            if (iMovieID != 0)
            {
                try
                {
                    XMMDBDataContext dbConnection = new XMMDBDataContext();

                    var vMovie = (from movie in dbConnection.t_movies where movie.ID == iMovieID select movie).Single();

                    // If movie was found.
                    if (vMovie != null && vMovie.ID != 0)
                    {
                        MovieID = vMovie.ID;
                        Name = vMovie.Name;
                        if (vMovie.Subtitle != null)
                            Subtitle = vMovie.Subtitle;

                        GenreID = vMovie.GenreID;

                        if (vMovie.Plot != null)
                            Plot = vMovie.Plot;

                        if (vMovie.Cast != null)
                            Cast = vMovie.Cast;

                        if (vMovie.Director != null)
                            Director = vMovie.Director;

                        if (vMovie.Year != null)
                            Year = (int)vMovie.Year;

                        // Get Files & Generate List
                        if(vMovie.Files != null)
                        {
                            if (vMovie.Files.Contains(";"))
                            {
                                string[] saFiles = vMovie.Files.Split(';');

                                if (saFiles != null && saFiles.Count() > 0)
                                {
                                    foreach (string sFile in saFiles)
                                    {
                                        if (sFile != String.Empty)
                                        {
                                            Files.Add(sFile);
                                        }
                                    }
                                }
                            }
                            else
                            {
                                Files.Add(vMovie.Files);
                            }
                            
                        }

                        if (vMovie.AudioInfo != null)
                        {
                            AudioInfo = new AudioInfo();
                            AudioInfo.buildFromBinary(vMovie.AudioInfo);
                        }

                        if (vMovie.VideoInfo != null)
                        {
                            VideoInfo = new VideoInfo();
                            VideoInfo.buildFromBinary(vMovie.VideoInfo);
                        }

                        HDLevel = vMovie.HDLevel;

                        DiskMediaID = vMovie.DiskMediaID;

                        if (vMovie.OnlineMediaID != null)
                            OnlineMediaID = vMovie.OnlineMediaID;

                        return true;
                    }
                }
                catch (SqlException ex)
                {
                    MessageBox.Show("Fehler beim Laden der Filmdaten: " + ex.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }

            return false;
        }

        /// <summary>
        /// Save objects as new Movie-Record in database.
        /// </summary>
        /// <returns>[true] if record was created successfully.</returns>
        public bool SaveNew()
        {
            if (Name != String.Empty && Files != null && Files.Count > 0)
            {
                try
                {
                    t_movies vMovie = new t_movies();
                    vMovie.Name = Name;
                    vMovie.Subtitle = Subtitle;
                    vMovie.GenreID = GenreID;
                    vMovie.Plot = Plot;
                    vMovie.Cast = Cast;
                    vMovie.Director = Director;
                    vMovie.Year = Year;

                    vMovie.Files = String.Empty;

                    // Get Files from List
                    foreach (string sFile in Files)
                    {
                        // Append Files to File-List-String
                        vMovie.Files += sFile + ";";
                    }

                    vMovie.AudioInfo = AudioInfo.ToBinary();
                    vMovie.VideoInfo = VideoInfo.ToBinary();
                    vMovie.HDLevel = HDLevel;
                    vMovie.DiskMediaID = DiskMediaID;
                    vMovie.OnlineMediaID = OnlineMediaID;

                    XMMDBDataContext dbConnection = new XMMDBDataContext();
                    dbConnection.t_movies.InsertOnSubmit(vMovie);
                    dbConnection.SubmitChanges();

                    return true;
                }
                catch (SqlException ex)
                {
                    MessageBox.Show("Fehler beim Speichern des neuen Films \"" + Name + "\": " + ex.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
            else
            {
                if (Name == String.Empty)
                    MessageBox.Show("Bitte geben Sie zuerst einen Name für den Film ein!", "Namen eingeben", MessageBoxButton.OK, MessageBoxImage.Exclamation);

                if (Files.Count <= 0)
                    MessageBox.Show("Bitte wählen Sie (eine) Video-Datei(en) für den Film aus!", "Datei(en) auswählen", MessageBoxButton.OK, MessageBoxImage.Exclamation);
            }

            return false;
        }

        /// <summary>
        /// Save changes to existing database-record.
        /// </summary>
        /// <returns>[true] if record was updated successfully.</returns>
        public bool SaveChanges()
        {
            if (MovieID != 0 && Name != String.Empty && Files != null && Files.Count > 0)
            {
                try
                {
                    XMMDBDataContext dbConnection = new XMMDBDataContext();

                    var vMovie = (from movie in dbConnection.t_movies where movie.ID == MovieID select movie).Single();

                    if (vMovie != null && vMovie.ID > 0)
                    {
                        vMovie.Name = Name;
                        vMovie.Subtitle = Subtitle;
                        vMovie.GenreID = GenreID;
                        vMovie.Plot = Plot;
                        vMovie.Cast = Cast;
                        vMovie.Director = Director;
                        vMovie.Year = Year;
                        vMovie.Files = String.Empty;
                        vMovie.DiskMediaID = DiskMediaID;
                        vMovie.OnlineMediaID = OnlineMediaID;

                        foreach (string sFile in Files)
                        {
                            vMovie.Files += sFile + ";";
                        }

                        vMovie.AudioInfo = AudioInfo.ToBinary();
                        vMovie.VideoInfo = VideoInfo.ToBinary();
                        vMovie.HDLevel = HDLevel;

                        dbConnection.SubmitChanges();

                        return true;
                    }
                }
                catch (SqlException ex)
                {
                    MessageBox.Show("Fehler beim Speichern der Änderungen für \"" + Name + "\": " + ex.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
            else
            {
                if (Name == String.Empty)
                    MessageBox.Show("Bitte geben Sie zuerst einen Name für den Film ein!", "Namen eingeben", MessageBoxButton.OK, MessageBoxImage.Exclamation);

                if (Files.Count <= 0)
                    MessageBox.Show("Bitte wählen Sie (eine) Video-Datei(en) für den Film aus!", "Datei(en) auswählen", MessageBoxButton.OK, MessageBoxImage.Exclamation);
            }

            return false;
        }

        /// <summary>
        /// Get a list of all available movies within the database.
        /// </summary>
        /// <param name="lblStatus">Status-Label to update.</param>
        /// <param name="pbStatus">Status-ProgressBar to update.</param>
        /// <returns></returns>
        public static List<Movie> getAllMovies(System.Windows.Controls.Label lblStatus, System.Windows.Controls.ProgressBar pbStatus)
        {
            List<Movie> lMovies = new List<Movie>();
            //pbStatus.IsIndeterminate = true;

            try
            {
                XMMDBDataContext dbConnection = new XMMDBDataContext();

                var vMovieCount = (from count in dbConnection.t_movies select count).Count();
                int iTotalMovies = 0;
                int iCurrentMovie = 0;

                if (int.Parse(vMovieCount.ToString()) > 0)
                {
                    iTotalMovies = int.Parse(vMovieCount.ToString());
                    //setStatus(lblStatus, iTotalMovies.ToString() + "Filme gefunden...", pbStatus, 0);

                    var vMovieIDs = from movieId in dbConnection.t_movies orderby movieId.Name select movieId.ID;

                    if (vMovieIDs != null && vMovieIDs.Count() > 0)
                    {
                        foreach (int iMovieID in vMovieIDs)
                        {
                            ++iCurrentMovie;
                            if (iMovieID > 0)
                            {
                                //setStatus(lblStatus, "Lade Film " + iCurrentMovie.ToString() + " von " + iTotalMovies.ToString() + "...", pbStatus, 50);
                                Objects.Movie oMovie = new Movie(iMovieID);
                                if (oMovie != null && oMovie.MovieID != 0)
                                {
                                    lMovies.Add(oMovie);
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Fehler beim Abrufen aller Filme in der Datenbank: " + ex.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
            }

            //setStatus(lblStatus, "Bereit...", pbStatus, 0);

            return lMovies;
        }

        /// <summary>
        /// Set Content of Status-Label and Value of Status-ProgressBar.
        /// </summary>
        /// <param name="lblStatus">Target Status-Label.</param>
        /// <param name="sNewStatus">New Status Message.</param>
        /// <param name="pbStatus">Target Status-ProgressBar.</param>
        /// <param name="iNewProgress">New Progress-Value.</param>
        private static void setStatus(System.Windows.Controls.Label lblStatus, string sNewStatus, System.Windows.Controls.ProgressBar pbStatus, int iNewProgress)
        {
            lblStatus.Dispatcher.Invoke(new setStatusMessageCallback(setStatusMessage), new object[] { lblStatus, sNewStatus });
        }

        /// <summary>
        /// Set Content of Status-Label.
        /// </summary>
        /// <param name="lblStatus">Target Status-Label.</param>
        /// <param name="sNewMessage">New Status-Message.</param>
        private static void setStatusMessage(System.Windows.Controls.Label lblStatus, string sNewMessage)
        {
            lblStatus.Content = sNewMessage;
        }

        private delegate void setStatusMessageCallback(System.Windows.Controls.Label lblStatus, string sNewMessage);

        /// <summary>
        /// Set Value of Status-ProgressBar.
        /// </summary>
        /// <param name="pbStatus">Target Status-ProgressBar.</param>
        /// <param name="iNewProgress">New Progress-Value.</param>
        private static void setStatusProgress(System.Windows.Controls.ProgressBar pbStatus, int iNewProgress)
        {
            if (iNewProgress > 100)
                iNewProgress = 100;
            pbStatus.Value = iNewProgress;
        }

        private delegate void setStatusProgressCallback(System.Windows.Controls.ProgressBar pbStatus, int iNewProgress);

        public static bool Delete(int iMovieID)
        {
            XMMDBDataContext dbConnection = new XMMDBDataContext();

            try
            {
                t_movies vMovie = (from movie in dbConnection.t_movies where movie.ID == iMovieID select movie).Single();
                if (vMovie != null && vMovie.ID > 0)
                {
                    dbConnection.t_movies.DeleteOnSubmit(vMovie);
                    dbConnection.SubmitChanges();

                    return true;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Fehler beim Löschen des Films '" + iMovieID.ToString() + "': " + ex.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
            }

            return false;
        }

        public bool Delete()
        {
            return Objects.Movie.Delete(MovieID);
        }

        public bool SeenBy(int iAudienceID)
        {
            if (MovieID != 0)
            {
                XMMDBDataContext dbConnection = new XMMDBDataContext();

                var vPlaybackCounter = (from playbacks in dbConnection.t_history where playbacks.MediaType == 1 && playbacks.MediaID == MovieID && playbacks.AudienceID == iAudienceID select playbacks).Count();

                if ((int)vPlaybackCounter > 0)
                {
                    return true;
                }
            }

            return false;
        }
    }

}
